package org.particles.gui;

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.HeadlessException;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Timer;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JToolBar;

import org.particles.common.CommonService;
import org.particles.common.CommonServiceImpl;
import org.particles.domain.sim.ElectronSimulation;
import org.particles.domain.sim.ElectronSimulation2;
import org.particles.domain.sim.ElectronSimulation3;
import org.particles.domain.sim.GravitySimulation;
import org.particles.domain.sim.MoleculeSimulation;
import org.particles.domain.sim.SimulationCase;
import org.particles.domain.sim.StringSimulation;
import org.particles.domain.sim.StringSimulation2;
import org.particles.gui.statistic.StatisticTask;
import org.particles.gui.statistic.UpdateStatisticAction;

public class MainFrame extends JFrame {
	private static final long serialVersionUID = 1963753839235322795L;
	private final WorldPanel worldPanel = new WorldPanel();

	public WorldPanel getWorldPanel() {
		return worldPanel;
	}

	public MainFrame() throws HeadlessException {
		super();
		initFrame();
	}

	public MainFrame(String title) throws HeadlessException {
		super(title);
		initFrame();
	}
	
	/**
	 * initializes world in the WorldPanel.
	 */
	private void initFrame() {
		// is daemon, because timer should die if application is exited.
		final WorldTimeTask task = new WorldTimeTask(this.worldPanel);
		final Timer timer = new Timer(true);
		timer.schedule(task, 1000, 50);
		
		// create available simulation factories
		final SimulationCase[] simulations = new SimulationCase[] {
			new ElectronSimulation(),
			new ElectronSimulation2(),
			new ElectronSimulation3(),
			new GravitySimulation(),
			new MoleculeSimulation(),
			new StringSimulation(),
			new StringSimulation2(),
		};
		
		// runAction
		final RunSimulationAction runAction = new RunSimulationAction();
		final CommonService commonService = new CommonServiceImpl();
		runAction.setCommonService(commonService);
		runAction.setWorldTimeTask(task);
		runAction.initAction();
		final JToolBar toolbar = new JToolBar("Simulation control");
		toolbar.add(runAction);
		
		// nextStateAction
		final NextStateAction nextStateAction = new NextStateAction();
		nextStateAction.setWorldPanel(worldPanel);
		nextStateAction.setCommonService(commonService);
		nextStateAction.setWorldTimeTask(task);
		nextStateAction.initAction();
		final PropertyChangeListener PlayIconSetter = new PropertyChangeListener() {
			@Override
			public void propertyChange(PropertyChangeEvent evt) {
				if(GuiUtil.PROP_TASKRUN.equals(evt.getPropertyName())) {
					runAction.setPlayIcon();
				}
			}
		};
		nextStateAction.addPropertyChangeListener(PlayIconSetter);
		toolbar.add(nextStateAction);
		
		// initSimAction
		final InitSimulationAction initSimAction = new InitSimulationAction();
		initSimAction.setCommonService(commonService);
		initSimAction.setWorldPanel(worldPanel);
		initSimAction.setWorldTimeTask(task);
		initSimAction.initAction();
		toolbar.add(initSimAction);
		
		// add toolbar
		final Container contentPane = getContentPane();
		toolbar.setOrientation(JToolBar.VERTICAL);
		contentPane.add(toolbar, BorderLayout.LINE_END);
		
		// add worldPanel
		final JPanel mainPanel = new JPanel(); // contains WorldPanel and SimCtrlPanel
		mainPanel.setLayout(new BorderLayout(5, 5));
		mainPanel.add(new JScrollPane(this.worldPanel), BorderLayout.CENTER);
		
		// add ctrlPanel
		final SimCtrlPanel ctrlPanel = new SimCtrlPanel(simulations);
		mainPanel.add(ctrlPanel, BorderLayout.EAST);
		initSimAction.setControlPanel(ctrlPanel);
		initSimAction.actionPerformed(GuiUtil.emptyActionEvent()); // initialize world
		
		// updateStatisticAction
		final UpdateStatisticAction updateStatisticAction = new UpdateStatisticAction();
		updateStatisticAction.setCommonService(commonService);
		updateStatisticAction.setSimCtrlPanel(ctrlPanel);
		updateStatisticAction.initAction();
		ctrlPanel.setUpdateStatAction(updateStatisticAction);
		
		// initialize statistic timer
		final StatisticTask statisticTask = new StatisticTask();
		statisticTask.setUpdateStatisticAction(updateStatisticAction);
		statisticTask.setWorldTimeTask(task);
		timer.schedule(statisticTask, 2000, 1000);
		
		// applyAction
		final ApplyParamsAction applyAction = new ApplyParamsAction();
		applyAction.setControlPanel(ctrlPanel);
		applyAction.setInitSimAction(initSimAction);
		applyAction.setWorldPanel(worldPanel);
		applyAction.setTask(task);
		ctrlPanel.setApplyAction(applyAction);
		
		// simulation selection listener
		final SimSelectAction simSelectListener = new SimSelectAction();
		simSelectListener.setWorldTimeTask(task);
		simSelectListener.setWorldPanel(worldPanel);
		simSelectListener.setControlPanel(ctrlPanel);
		simSelectListener.addPropertyChangeListener(PlayIconSetter);
		ctrlPanel.addSimSelectListener(simSelectListener);
		
		contentPane.add(mainPanel, BorderLayout.CENTER);
	}
	
	public static void main(String[] argv) {
		final MainFrame mainFrame = new MainFrame("Particle world");
		mainFrame.setDefaultCloseOperation(EXIT_ON_CLOSE);
		mainFrame.setSize(1080, 670);
		mainFrame.setVisible(true);
	}
}
